package com.itheima.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.common.constant.MessageConstant;
import com.itheima.common.constant.RedisConstant;
import com.itheima.common.entity.PageResult;
import com.itheima.common.entity.QueryPageBean;
import com.itheima.common.exception.DataNotFoundException;
import com.itheima.common.exception.DuplicateDataException;
import com.itheima.common.exception.FileUploadFailedException;
import com.itheima.common.exception.RedisNotAvailableException;
import com.itheima.common.utils.AliOssUtil;
import com.itheima.mapper.OrderMapper;
import com.itheima.mapper.SetmealCheckGroupMapper;
import com.itheima.mapper.SetmealMapper;
import com.itheima.pojo.Setmeal;
import com.itheima.service.FreeMarkerService;
import com.itheima.service.SetmealService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnectionCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

@Service
@Slf4j
public class SetmealServiceImpl implements SetmealService {

    @Autowired
    private SetmealMapper setmealMapper;
    @Autowired
    private SetmealCheckGroupMapper setmealCheckGroupMapper;
    @Autowired
    private AliOssUtil aliOssUtil;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private FreeMarkerService freeMarkerService;
    @Autowired
    private OrderMapper orderMapper;

    /**
     * 分页查询
     * @param queryPageBean
     * @return
     */
    @Override
    public PageResult pageQuery(QueryPageBean queryPageBean) {
        PageHelper.startPage(queryPageBean.getCurrentPage(), queryPageBean.getPageSize());
        Page<Setmeal> page = setmealMapper.pageQuery(queryPageBean.getQueryString());
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 添加套餐
     *
     * @param setmeal
     * @param checkgroupIds
     */
    @Override
    @Transactional
    public void addSetmeal(Setmeal setmeal, List<Integer> checkgroupIds) {
        // TODO 判断套餐编码等是否重复
        // 添加套餐基本信息
        setmealMapper.insert(setmeal);
        // 如果套餐中image不为空,则将值添加到redis数据库图片数组缓存中
        String imgUrl = setmeal.getImg();
        if (imgUrl != null && !imgUrl.isEmpty()) {
            redisTemplate.boundSetOps(RedisConstant.SETMEAL_PIC_DB_RESOURCES).add(imgUrl);
        }
        // 添加套餐和检查组关联关系
        setmealCheckGroupMapper.insertBatch(setmeal.getId(), checkgroupIds);
        // 生成套餐详情页面
        freeMarkerService.generateSetmealInfoFile("mobile_setmeal_detail" ,setmeal.getId());
        // 生成/刷新套餐列表页面
        freeMarkerService.generateSetmealFile("mobile_setmeal");
    }

    /**
     * 根据id删除套餐
     *
     * @param id
     */
    @Override
    @Transactional
    public void deleteById(Integer id) {
        // 检查套餐是否被预约
        Integer count = orderMapper.countBySetmealId(id);
        if (count > 0) {
            throw new DuplicateDataException(MessageConstant.DELETE_SETMEAL_FAIL);
        }
        // 获取当前套餐对象
        Setmeal setmeal = finById(id);
        // 判断图片信息是否存在
        String imgUrl = setmeal.getImg();
        if (imgUrl != null && !imgUrl.isEmpty()) {
            // 将图片信息添加到redis缓存中(无论是否已经存在) --> 阿里云图片集合
            log.info("添加redis缓存到Aliyun图片集合:{}", imgUrl);
            redisTemplate.boundSetOps(RedisConstant.SETMEAL_PIC_RESOURCES).add(imgUrl);
            // 将图片路径从redis缓存中移除(无论是否已经存在) --> 数据库图片集合
            log.info("移除redis缓存到数据库图片集合:{}", imgUrl);
            redisTemplate.boundSetOps(RedisConstant.SETMEAL_PIC_DB_RESOURCES).remove(imgUrl);
        }
        // 删除套餐
        setmealMapper.deleteById(id);
        // 删除套餐和检查组关联关系
        setmealCheckGroupMapper.deleteBySetmealId(id);
    }

    /**
     * 根据id查询套餐
     *
     * @param id
     * @return
     */
    @Override
    public Setmeal finById(Integer id) {
        Setmeal setmeal = new Setmeal();
        setmeal.setId(id);
        // 条件查询
        List<Setmeal> setmeals = setmealMapper.select(setmeal);
        // 判断查询结果
        if (setmeals == null || setmeals.isEmpty()) {
            // 如果未查询到数据，抛出异常
            throw new DataNotFoundException(MessageConstant.QUERY_SETMEAL_FAIL);
        }
        return setmeals.get(0);
    }

    /**
     * 编辑套餐
     *
     * @param setmeal
     * @param checkgroupIds
     */
    @Override
    @Transactional
    public void editSetmeal(Setmeal setmeal, List<Integer> checkgroupIds) {
        // TODO 判断套餐编码等是否重复
        // 获取当前套餐对象(未修改)的图片信息
        Setmeal oldSetmeal = finById(setmeal.getId());
        String oldImgUrl = oldSetmeal.getImg();

        // 更新套餐基本信息
        setmealMapper.update(setmeal);
        // 如果套餐中image被修改,则将新的值添加到redis缓存中
        String imgUrl = setmeal.getImg();
        if (!Objects.equals(oldImgUrl, imgUrl)) {
            if (oldImgUrl != null && !oldImgUrl.isEmpty()) {
                // 将旧图片信息添加到redis缓存中(无论是否已经存在) --> 阿里云图片集合
                redisTemplate.boundSetOps(RedisConstant.SETMEAL_PIC_RESOURCES).add(oldImgUrl);
                // 将旧图片路径从redis缓存中移除(无论是否已经存在) --> 数据库图片集合
                redisTemplate.boundSetOps(RedisConstant.SETMEAL_PIC_DB_RESOURCES).remove(oldImgUrl);
            }
            // 如何新的图片路径不为空,将新的图片信息添加到redis缓存中 --> 数据库图片集合
            if (imgUrl != null && !imgUrl.isEmpty()) {
                redisTemplate.boundSetOps(RedisConstant.SETMEAL_PIC_DB_RESOURCES).add(imgUrl);
            }
        }
        // 删除套餐和检查组关联关系
        setmealCheckGroupMapper.deleteBySetmealId(setmeal.getId());
        // 如果checkgroupIds不为空,添加套餐和检查组关联关系
        if (checkgroupIds != null && !checkgroupIds.isEmpty()){
            setmealCheckGroupMapper.insertBatch(setmeal.getId(), checkgroupIds);
        }
        // 生成套餐详情页面
        freeMarkerService.generateSetmealInfoFile("mobile_setmeal_detail" ,setmeal.getId());
    }

    /**
     * 上传图片
     *
     * @param imgFile
     * @return
     */
    @Override
    public String upload(MultipartFile imgFile) {
        // 判断当前Redis是否可以使用
        if (!isRedisAvailable()) {
            throw new RedisNotAvailableException(MessageConstant.PIC_UPLOAD_FAIL);
        }
        try {
            // 获取文件后缀,生成新的文件名
            int index = Objects.requireNonNull(imgFile.getOriginalFilename()).lastIndexOf(".");
            String suffix = imgFile.getOriginalFilename().substring(index);
            String fileName = UUID.randomUUID().toString() + suffix;
            // 上传图片,获取图片的url
            String imgUrl = aliOssUtil.upload(imgFile.getBytes(), fileName);
            // 将token添加到redis缓存当中
            log.info("添加redis缓存到aliyun图片集合:{}", imgUrl);
            redisTemplate.boundSetOps(RedisConstant.SETMEAL_PIC_RESOURCES).add(imgUrl);
            // 返回图片的url
            return imgUrl;
        } catch (IOException e) {
            throw new FileUploadFailedException(MessageConstant.PIC_UPLOAD_FAIL);
        }
    }

    /**
     * 检查 Redis 连接是否可用
     * @return true 可用,  false 不可用
     */
    public boolean isRedisAvailable() {
        try {
            // 使用 PING 命令检查 Redis 连接
            String result = redisTemplate.execute(RedisConnectionCommands::ping);
            return "PONG".equals(result);
        } catch (Exception e) {
            log.error("Redis 连接不可用");
            return false;
        }
    }
}
